//
//  UiViewExtension.swift
//  PMS
//
//  Created by haotianz on 15/10/27.
//  Copyright © 2015年 途家. All rights reserved.
//

import Foundation

extension UIView {
    public func drawShadow(_ radius: CGFloat = 1, offset: CGSize = CGSize(width: 0, height: -1), opacity: Float = 0.6, color: UIColor? = CommonColors.c_c2c2c2) {
        self.layer.shadowRadius = radius
        self.layer.shadowOffset = offset
        self.layer.shadowOpacity = opacity
        self.layer.shadowColor = color?.cgColor
    }
    
    public func drawShadowLine() {
        let shadowLine = UIView()
        shadowLine.backgroundColor = CommonColors.c_c2c2c2
        shadowLine.frame = CGRect(x: 0, y: -CommonDefine.kPixel, width: self.frame.width, height: CommonDefine.kPixel)
        self.addSubview(shadowLine)
    }
  
}

extension UIView {
    
    public func shake() {
        self.shake(nil)
    }
    
    public func shakeOff(_ message: String, shake : Bool = true) {
        self.shake(message, offset: 0, shakeDur: 0.25, msgDur: 1.25, isNeedShake: shake)
    }
    
    public func shake(_ message : String?, offset : CGFloat = 5, shakeDur : Double = 0.5, msgDur : Double = 1,isNeedShake:Bool = true){
        let leftOffsets = [-offset, 2*offset, -offset*3/2, offset/2]
        let avgDur = shakeDur / Double(leftOffsets.count)
        let maxWid = CommonDefine.kScreenWidth * 0.8
        var lblMsg : UILabel!
        if message != nil && !message!.isEmpty {
            lblMsg = UILabel()
            lblMsg.text = message
            lblMsg.textAlignment = .center
            lblMsg.textColor = UIColor.white
            lblMsg.backgroundColor = CommonColors.c_666666
            lblMsg.numberOfLines = 0
            lblMsg.alpha = 0.8
            let newSize = lblMsg.sizeThatFits(CGSize(width: maxWid, height: 1000))
            let wid = newSize.width + 20
            let het = newSize.height + 20
            lblMsg.layer.cornerRadius = 8
            lblMsg.layer.masksToBounds = true
            lblMsg.frame = CGRect(x: self.w/2-wid/2, y: self.h/2-het/2, width: wid, height: het)
        }
        let old = self.frame
        
        for (index,off) in leftOffsets.enumerated() {
            UIView.animate(withDuration: avgDur, delay: avgDur*Double(index), options: UIView.AnimationOptions(), animations: { () -> Void in
                if isNeedShake == true{self.transform = CGAffineTransform(translationX: off, y: 0)}
                }, completion: { (success) -> Void in
                    if success && index == 0 && lblMsg != nil {
                        self.addSubview(lblMsg)
                        UIView.animate(withDuration: msgDur, delay: shakeDur, options: UIView.AnimationOptions(), animations: { () -> Void in
                            lblMsg.alpha = 0
                            }, completion: { s in
                                lblMsg.removeFromSuperview()
                                lblMsg = nil
                            }
                        )
                    }
                    if index == leftOffsets.count - 1 {
                        self.frame = old //adjustment.
                    }
            })
        }
    }
}


extension UIView {
    
    /// Get closest superview of indicate type
    public func getClosestSuperViewOf<TView>() -> TView? {
        if let tv = self as? TView { return tv }
        return getClosestSuperViewOf(self)
    }
    
    fileprivate func getClosestSuperViewOf<TView>(_ root : UIView) -> TView? {
        if root.superview == nil { return nil }
        if let tv = root.superview! as? TView { return tv }
        return getClosestSuperViewOf(root.superview!)
    }
    
    /// Get all subview of indicate type.
    public func getAllSubViewOf<TView>() -> [TView] {
        var result = [TView]()
        if let tv = self as? TView { result.append(tv) }
        getAllSubViewOf(self, result : &result)
        return result
    }
    
    fileprivate func getAllSubViewOf<TView>(_ root : UIView, result : inout [TView]) {
        for item in root.subviews {
            if let tv = item as? TView {
                result.append(tv)
            }
            getAllSubViewOf(item, result : &result)
        }
    }
    
    /// Get first subview of indicate type.
    public func getClosestSubViewOf<TView>() -> TView? {
        return getClosestSubViewOf(self)
    }
    
    fileprivate func getClosestSubViewOf<TView>(_ root: UIView) -> TView? {
        if let tv = root as? TView {
            return tv
        } else {
            for sub in root.subviews {
                if let tv : TView = getClosestSubViewOf(sub) {
                    return tv
                }
            }
        }
        return nil
    }
    
    /// Get view controller which contains current view.
    public func getViewController() -> UIViewController? {
        var next : UIView? = self
        while (next != nil) {
            let responder = next?.next
            if let controller = responder as? UIViewController {
                return controller
            }
            next = next?.superview
        }
        return nil
    }
    
    /// Get current display view controller. Popup view added to other non-keywindow will get 'nil'.
    public class func getCurrentViewController() -> UIViewController? {
        var window = UIApplication.shared.keyWindow
        if window?.windowLevel != UIWindow.Level.normal {
            window = UIApplication.shared.windows.first({ $0.windowLevel == UIWindow.Level.normal }) //must have one
        }
        
        let frontView = window?.subviews.first
        let responder = frontView?.next as? UIViewController
        return responder ?? window?.rootViewController
    }
    
    public class func getCurrentNormalWindow() -> UIWindow? {
        var window = UIApplication.shared.keyWindow
        if window?.windowLevel != UIWindow.Level.normal {
            window = UIApplication.shared.windows.first({ $0.windowLevel == UIWindow.Level.normal }) //must have one
        }
        return window
    }
}


extension UIView {
    public func createEqualDivisionLabels(_ range : CGRect, div : Int, setting : ((Int,UILabel)->Void)? = nil) -> [UILabel] {
        if div <= 0 { return [UILabel]() }
        let avg = 1 / CGFloat(div)
        var avgWeight = [CGFloat]()
        for _ in 0..<div {
            avgWeight.append(avg)
        }
        return createDivisionLabels(range, div: div, weight: avgWeight, setting: setting)
    }
    
    public func createDivisionLabels(_ range : CGRect, div : Int, weight : [CGFloat], setting : ((Int,UILabel)->Void)? = nil) -> [UILabel] {
        if div <= 0 { return [UILabel]() }
        var startX : CGFloat = range.origin.x
        var result = [UILabel]()
        for index in 0..<div {
            let width = range.width * weight[index]
            let lbl = UILabel(frame: CGRect(x: startX, y: range.origin.y, width: width, height: range.height))
            setting?(index,lbl)
            self.addSubview(lbl)
            result.append(lbl)
            startX += width
        }
        return result
    }
    
    
    public func createEqualDivisionEdgets(_ range : CGRect, lines : Int, setting : ((Int, UIView)->Void)? = nil) {
        if lines <= 0 { return }
        let avg = 1 / CGFloat(lines+1)
        var avgWeight = [CGFloat]()
        for _ in 0...lines {
            avgWeight.append(avg)
        }
        self.createDivisionEdgets(range, lines: lines, weight: avgWeight, setting: setting)
    }
    
    public func createDivisionEdgets(_ range : CGRect, lines : Int, weight : [CGFloat], setting : ((Int, UIView)->Void)? = nil) {
        if lines <= 0 { return }
        var startX = range.width * weight[0] + range.origin.x
        for index in 0..<(lines) {
            let view = UIView(frame: CGRect(x: startX, y: range.origin.y, width: CommonDefine.kPixel, height: range.height))
            setting?(index,view)
            self.addSubview(view)
            if index < lines - 1 { startX += range.width * weight[index+1] }
        }
    }
}

extension UIView {
    /// animates run one after another
    public class func animatesRun(_ animates : (animate:()->Void,duration:TimeInterval)...) {
        animatesRun(animates)
    }
    
    /// animates run one after another
    public class func animatesRun(_ animates : (animate:()->Void, duration: TimeInterval, delay: TimeInterval)...) {
        animatesRun(animates)
    }
    
    /// animates run one after another
    public class func animatesRun(_ animates : (animate:()->Void, duration: TimeInterval, delay: TimeInterval, options : UIView.AnimationOptions)...) {
        animatesRun(animates)
    }
    
    /// animates run one after another
    public class func animatesRun(_ animates : [(animate:()->Void,duration:TimeInterval)]) {
        let defaultDelay : TimeInterval = 0
        let converts = animates.map({ (animate: $0.animate, duration: $0.duration, delay: defaultDelay) })
        animatesRun(converts)
    }
    
    /// animates run one after another
    public class func animatesRun(_ animates: [(animate:()->Void, duration: TimeInterval, delay: TimeInterval)]) {
        let defaultOptions : UIView.AnimationOptions = .curveLinear
        let converts = animates.map({ (animate: $0.animate, duration: $0.duration, delay: $0.delay, options: defaultOptions) })
        animatesRun(converts)
    }
    
    /// animates run one after another
    public class func animatesRun(_ animates: [(animate:()->Void, duration: TimeInterval, delay: TimeInterval, options : UIView.AnimationOptions)]) {
        var lastAnimate : (()->Void)? = nil
        for item in animates.reversed() {
            if lastAnimate == nil {
                lastAnimate = {
                    UIView.animate(withDuration: item.duration, delay: item.delay, options: item.options, animations: item.animate, completion: nil)
                }
            } else {
                let temp = lastAnimate! //this is very important, make a local reference copy.
                lastAnimate = {
                    UIView.animate(withDuration: item.duration, delay: item.delay, options: item.options, animations: item.animate, completion: { success in if success { temp() } })
                }
            }
        }
        lastAnimate?()
    }
}

extension UIView {

    public func setCorner(_ radius : CGFloat) {
        self.layer.cornerRadius = radius
        self.layer.masksToBounds = true
    }

    public func setBorder(width borderWidth : CGFloat = CommonDefine.kPixel, color borderColor : UIColor) {
        self.layer.borderColor = borderColor.cgColor
        self.layer.borderWidth = borderWidth
    }

    public func setBorderNull() {
        self.layer.borderWidth = 0
    }
}

extension UIView {
    
    /// self.superview?.bringSubviewToFront
    public func toFront() {
        self.superview?.bringSubviewToFront(self)
    }
}

// easy frame
extension UIView {
    var w: CGFloat {
        get { return self.frame.width }
        set { self.frame = CGRect(x: self.x, y: self.y, width: newValue, height: self.h) }
    }
    
    var h: CGFloat {
        get { return self.frame.height }
        set { self.frame = CGRect(x: self.x, y: self.y, width: self.w, height: newValue) }
    }
    
    var x: CGFloat {
        get { return self.frame.origin.x }
        set { self.frame = CGRect(x: newValue, y: self.y, width: self.w, height: self.h) }
    }
    
    var y: CGFloat {
        get { return self.frame.origin.y }
        set { self.frame = CGRect(x: self.x, y: newValue, width: self.w, height: self.h) }
    }
    
    var o: CGPoint {
        get { return self.frame.origin }
        set { self.frame = CGRect(origin: newValue, size: self.s) }
    }
    
    var s: CGSize {
        get { return self.frame.size }
        set { self.frame = CGRect(origin: self.o, size: newValue) }
    }
    
    var r: CGFloat {
        get { return self.x + self.w }
    }
    
    var b: CGFloat {
        get { return self.y + self.h }
    }
}
